package com.shawn.spring.boot.jdbc.dao;

import com.shawn.spring.boot.jdbc.entity.User;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

/**
 * @author shawn
 * @since 2020/8/27
 */
@Repository
public class UserDao extends CommonDao<User, Integer> {

  @Autowired private SimpleJdbcInsert jdbcInsert;

  @Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

  private final JdbcTemplate jdbcTemplate;

  public UserDao(JdbcTemplate jdbcTemplate) {
    super(jdbcTemplate);
    this.jdbcTemplate = jdbcTemplate;
  }

  private static final String INSERT_SQL =
      "insert into t_user (username, password, nickname, email, create_time, update_time, is_deleted) values (?,?,?,?,?,?,?)";

  private static final String SELECT_SQL = "select * from t_user where is_deleted = false";

  private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  public void batchInsertWithBatchPreparedStatementSetter(List<User> users) {
    jdbcTemplate.batchUpdate(
        INSERT_SQL,
        new BatchPreparedStatementSetter() {
          @Override
          public void setValues(PreparedStatement ps, int i) throws SQLException {
            User user = users.get(i);
            ps.setString(1, user.getUsername());
            ps.setString(2, user.getPassword());
            ps.setString(3, user.getNickname());
            ps.setString(4, user.getEmail());
            ps.setDate(5, new java.sql.Date(user.getCreateTime().getTime()));
            ps.setDate(6, new java.sql.Date(user.getUpdateTime().getTime()));
            ps.setBoolean(7, user.isDeleted());
          }

          @Override
          public int getBatchSize() {
            return users.size();
          }
        });
  }

  public void batchInsertWithList(List<User> users) {
    List<Object[]> arrList = new ArrayList<>();
    for (User user : users) {
      List<Object> objs = new ArrayList<>();
      objs.add(user.getUsername());
      objs.add(user.getPassword());
      objs.add(user.getNickname());
      objs.add(user.getEmail());
      objs.add(user.getCreateTime());
      objs.add(user.getUpdateTime());
      objs.add(user.isDeleted());
      arrList.add(objs.toArray());
    }
    jdbcTemplate.batchUpdate(INSERT_SQL, arrList);
  }

  public void batchInsertWithNamedParams(List<User> users) {
    String sql =
        "insert into t_user (username, password, nickname, email, create_time, update_time) "
            + "values (:username, :password, :nickname, :email, :createTime, :updateTime)";
    namedParameterJdbcTemplate.batchUpdate(sql, SqlParameterSourceUtils.createBatch(users));
  }

  public int insertReturnKey(User user) {
    Number key = jdbcInsert.withTableName(getTableName()).executeAndReturnKey(toMap(user));
    return key.intValue();
  }

  private Map<String, Object> toMap(User user) {
    Map<String, Object> map = new HashMap<>();
    map.put("is_deleted", user.isDeleted());
    String username = user.getUsername();
    if (StringUtils.hasText(username)) {
      map.put("username", username);
    }
    String password = user.getPassword();
    if (StringUtils.hasText(password)) {
      map.put("password", password);
    }
    String nickname = user.getNickname();
    if (StringUtils.hasText(nickname)) {
      map.put("nickname", nickname);
    }
    String email = user.getEmail();
    if (StringUtils.hasText(email)) {
      map.put("email", email);
    }
    Date createTime = user.getCreateTime();
    if (null != createTime) {
      map.put("create_time", createTime);
    }
    Date updateTime = user.getUpdateTime();
    if (null != updateTime) {
      map.put("update_time", updateTime);
    }
    int id = user.getUserId();
    if (id != 0) {
      map.put("user_id", id);
    }
    return map;
  }
}
